# -*- coding: utf-8 -*-
"""数据模型模块"""

from typing import Optional

from .const import *


class GameBase:
    def __init__(self, jsonObj):
        self._json: dict = jsonObj

    def __getattr__(self, name):
        if name in self._json:
            return self._json[name]
        raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")

    def toDict(self) -> dict:
        return self._json


class GameState(GameBase):
    """游戏状态类"""

    def __init__(self, jsonObj):
        super().__init__(jsonObj)
        self.battleId: str = self._json['battleId']
        self.playerId: str = self._json['playerId']
        self.round: int = self._json['round']
        self.timeLimit: int = self._json['timeLimit']
        self.battleState = GameStateModel(self._json['battleState'])
        # battleState
        self.currentRound = self.battleState.currentRound
        self.width = self.battleState.width
        self.height = self.battleState.height
        # units
        self.units: dict[int, UnitModel] = {}
        for playerId, player in self.battleState.players.items():
            self.units.update(player.units)
        # buildings
        self.buildings: dict[int, BuildingModel] = {}
        for playerId, player in self.battleState.players.items():
            self.buildings.update(player.buildings)

    def getMyPlayer(self) -> 'PlayerInfoModel':
        if self.playerId not in self.battleState.players:
            # 如果playerId不存在，尝试查找匹配的玩家
            for player_id, player in self.battleState.players.items():
                if player_id.startswith(self.playerId.split('(')[0]):
                    return player
            # 如果还是找不到，返回第一个玩家或抛出更有意义的错误
            if self.battleState.players:
                return list(self.battleState.players.values())[0]
            else:
                raise KeyError(f"No players found in battleState. Available players: {list(self.battleState.players.keys())}, requested playerId: {self.playerId}")
        return self.battleState.players[self.playerId]

    def getEnemyPlayer(self) -> 'PlayerInfoModel':
        for playerId, player in self.battleState.players.items():
            if playerId != self.playerId:
                return player

    def getUnit(self, id: int) -> Optional['UnitModel']:
        return self.units.get(id, None)

    def getBuilding(self, id: int) -> Optional['BuildingModel']:
        return self.buildings.get(id, None)

    def getTilde(self, x: int, y: int) -> Optional['TildeModel']:
        return self.battleState.terrain[y][x]


class GameStateModel(GameBase):
    """游戏状态类"""

    def __init__(self, jsonObj):
        super().__init__(jsonObj)
        self.status = str(self._json['status'])
        self.initialized = bool(self._json['initialized'])
        self.battleEnded = bool(self._json['battleEnded'])
        self.currentRound = int(self._json['currentRound'])
        self.width = int(self._json['map']['width'])
        self.height = int(self._json['map']['height'])
        # terrain
        self.terrain: list[list[TildeModel]] = [None] * len(self._json['map']['terrain'])
        for i, row in enumerate(self._json['map']['terrain']):
            self.terrain[i] = [None] * len(row)
            for j, tile in enumerate(row):
                self.terrain[i][j] = TildeModel(tile)
        # players
        self.players: dict[str, PlayerInfoModel] = {}
        for playerId, player in self._json['players'].items():
            self.players[playerId] = PlayerInfoModel(player)


class UnitModel(GameBase):
    """单位模型类"""

    def __init__(self, jsonObj):
        super().__init__(jsonObj)
        self.id = int(self._json['id'])
        self.type = UnitType(self._json['type'])
        self.hp = int(self._json['hp'])
        self.attack = int(self._json['attack'])
        self.speed = int(self._json['speed'])
        self.x = int(self._json['position']['x'])
        self.y = int(self._json['position']['y'])
        # config
        self.config = UNIT_CONFIG[self.type]


class BuildingModel(GameBase):
    """建筑模型类"""

    def __init__(self, jsonObj):
        super().__init__(jsonObj)
        self.id = int(self._json['id'])
        self.type = BuildingType(self._json['type'])
        self.player = str(self._json['player'])
        self.hp = int(self._json['hp'])
        self.attack = int(self._json['attack'])
        self.x = int(self._json['position']['x'])
        self.y = int(self._json['position']['y'])
        # config
        self.config = BUILDING_CONFIG[self.type]


class TildeModel(GameBase):
    """地块模型类"""

    def __init__(self, jsonObj):
        super().__init__(jsonObj)
        self.type = TildeType(self._json['type'])
        self.building = int(self._json['building']) if self._json.get('building') else None
        self.unit = int(self._json['unit']) if self._json.get('unit') else None
        self.player = str(self._json['player']) if self._json.get('player') else None
        # config
        self.config = RESOURCE_CONFIG.get(self.type, None)


class PlayerInfoModel(GameBase):
    """玩家信息模型"""

    def __init__(self, jsonObj):
        super().__init__(jsonObj)
        self.id = str(self._json['id'])
        self.playerType = str(self._json['playerType'])
        self.rmb = int(self._json['rmb'])
        self.baseHealth = int(self._json['baseHealth'])
        # units
        self.units: dict[int, UnitModel] = {}
        for i, unit in enumerate(self._json['units']):
            if 'id' in unit:
                self.units[int(unit['id'])] = UnitModel(unit)
        # buildings
        self.buildings: dict[int, BuildingModel] = {}
        for i, building in enumerate(self._json['buildings']):
            if 'id' in building:
                obj = BuildingModel(building)
                self.buildings[int(building['id'])] = obj
                if obj.type == BuildingType.base:
                    self.baseBuilding = obj


class CommandBase:
    def __init__(self, input: GameState, type: str, param: dict):
        player = input.playerId
        round = input.round
        self._json = {
            'type': type,
            'player': player,
            'round': round,
            'param': param,
        }

    def toDict(self) -> dict:
        return self._json


class MoveCommand(CommandBase):
    """移动命令类

    Args:
        id: 单位ID
        x,y: 目标位置
    """

    def __init__(self, input: GameState, id: int, x: int, y: int):
        unit = input.getUnit(id)
        x = x - unit.x
        y = y - unit.y
        super().__init__(
            input,
            CommandType.move,
            {
                'self': {
                    'type': EntityType.unit,
                    'utype': unit.type,
                    'id': id,
                },
                'offsetPosition': {
                    'x': x,
                    'y': y,
                },
            },
        )


class AttackCommand(CommandBase):
    """创建完整的攻击命令

    Args:
        id: 单位ID
        targetId: 目标单位ID

    Returns:
        完整的攻击命令
    """

    def __init__(
        self,
        input: GameState,
        id: int,
        targetId: int,
        selfType: EntityType = EntityType.unit,
        targetType: EntityType = EntityType.unit,
    ):
        # 攻击者可能是单位 也可能是建筑
        attacker = input.getUnit(id)
        if selfType == EntityType.unit:
            attacker = input.getUnit(id)
        else:
            attacker = input.getBuilding(id)
        # 攻击目标可能是单位 也可能是建筑
        if targetType == EntityType.unit:
            target = input.getUnit(targetId)
        else:
            target = input.getBuilding(targetId)

        x = target.x - attacker.x
        y = target.y - attacker.y
        super().__init__(
            input,
            CommandType.attack,
            {
                'self': {
                    'type': selfType,
                    'utype': attacker.type,
                    'id': id,
                },
                'target': {
                    'type': targetType,
                    'utype': target.type,
                    'id': targetId,
                },
                'offsetPosition': {
                    'x': x,
                    'y': y,
                },
            },
        )


class BuildCommand(CommandBase):
    """创建完整的建造命令

    Args:
        id: 建造者单位
        type: 建筑类型
        x, y: 建造位置

    Returns:
        完整的建造命令
    """

    def __init__(self, input: GameState, id: int, type: BuildingType, x: int, y: int):
        unit = input.getUnit(id)
        x = x - unit.x
        y = y - unit.y
        super().__init__(
            input,
            CommandType.build,
            {
                'self': {
                    'type': EntityType.unit,
                    'utype': unit.type,
                    'id': id,
                },
                'target': {
                    'type': EntityType.building,
                    'utype': type,
                },
                'offsetPosition': {
                    'x': x,
                    'y': y,
                },
            },
        )


class SwapCommand(CommandBase):
    """创建生产命令

    Args:
        id: 建造者单位
        type: 生产单位类型
        x, y: 建造位置

    Returns:
        完整的建造命令
    """

    def __init__(self, input: GameState, id: int, type: UnitType, x: int, y: int):
        building = input.getBuilding(id)
        x = x - building.x
        y = y - building.y
        super().__init__(
            input,
            CommandType.swap,
            {
                'self': {
                    'type': EntityType.building,
                    'utype': building.type,
                    'id': id,
                },
                'target': {
                    'type': EntityType.unit,
                    'utype': type,
                },
                'offsetPosition': {
                    'x': x,
                    'y': y,
                },
            },
        )


class HealCommand(CommandBase):
    """创建治疗命令

    Args:
        id: 治疗单位
        targetId: 被治疗单位

    Returns:
        完整的建造命令
    """

    def __init__(self, input: GameState, id: int, targetId: int):
        unit = input.getUnit(id)
        targetUnit = input.getUnit(targetId)
        x = targetUnit.x - unit.x
        y = targetUnit.y - unit.y
        super().__init__(
            input,
            CommandType.heal,
            {
                'self': {
                    'type': EntityType.unit,
                    'utype': unit.type,
                    'id': id,
                },
                'target': {
                    'type': EntityType.unit,
                    'utype': targetUnit.type,
                    'id': targetId,
                },
                'offsetPosition': {
                    'x': x,
                    'y': y,
                },
            },
        )


class CollectCommand(CommandBase):
    """创建采集命令

    Args:
        id: 采集者单位

    Returns:
        完整的建造命令
    """

    def __init__(self, input: GameState, id: int, x: int, y: int):
        unit = input.getUnit(id)
        tilde = input.getTilde(x, y)
        x = x - unit.x
        y = y - unit.y
        super().__init__(
            input,
            CommandType.collect,
            {
                'self': {
                    'type': EntityType.unit,
                    'utype': unit.type,
                    'id': id,
                },
                'target': {
                    'type': EntityType.terrain,
                    'utype': tilde.type,
                },
                'offsetPosition': {
                    'x': x,
                    'y': y,
                },
            },
        )
